home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ohlutil.zip / HEAD.C < prev    next >
C/C++ Source or Header  |  1990-05-31  |  8KB  |  337 lines

  1. /* head -- output first part of file(s)
  2.    Copyright (C) 1989, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Usage: head [-n #] [-lbcqv] [+number #] [+lines] [+blocks] [+chars]
  19.           [+quiet] [+silent] [+verbose] [file...]
  20.  
  21.           head [-#lbcqv] [file...]
  22.  
  23.    Options:
  24.    -n, +number #    Print first # items (default 10).
  25.    -l, +lines        Head by lines (the default).
  26.    -b, +blocks        Head by 512-byte blocks.
  27.    -c, +chars        Head by characters.
  28.    -q, +quiet, +silent    Never print filename headers.
  29.    -v, +verbose        Always print filename headers.
  30.  
  31.    Reads from standard input if no files are given or when a filename of
  32.    ``-'' is encountered.
  33.    By default, filename headers are printed only if more than one file
  34.    is given.
  35.  
  36.    David MacKenzie <djm@ai.mit.edu> */
  37.  
  38. #include <stdio.h>
  39. #include <ctype.h>
  40. #include <sys/types.h>
  41. #include "getopt.h"
  42. #include "system.h"
  43.  
  44. #ifdef STDC_HEADERS
  45. #include <errno.h>
  46. #include <stdlib.h>
  47. #define ISDIGIT(c) (isdigit ((unsigned char) (c)))
  48. #else
  49. #define ISDIGIT(c) (isascii (c) && isdigit (c))
  50.  
  51. extern int errno;
  52. #endif
  53.  
  54. /* Number of lines/chars/blocks to head. */
  55. #define DEFAULT_NUMBER 10
  56.  
  57. #define BLOCKSIZE 512
  58.  
  59. /* Size of atomic reads. */
  60. #define BUFSIZE (BLOCKSIZE*8)
  61.  
  62. /* Masks for the operation mode.  If neither CHARS nor BLOCKS is set,
  63.    head operates by lines. */
  64. #define CHARS 1            /* Head in chars. */
  65. #define BLOCKS 2        /* Head in blocks. */
  66. #define HEADERS 4        /* Write filename headers. */
  67.  
  68. /* When to print the filename banners. */
  69. enum header_mode
  70. {
  71.   multiple_files, always, never
  72. };
  73.  
  74. int head ();
  75. int head_chars ();
  76. int head_file ();
  77. int head_lines ();
  78. long atou ();
  79. void error ();
  80. void usage ();
  81. void write_header ();
  82. void xwrite ();
  83.  
  84. /* The name this program was run with. */
  85. char *program_name;
  86.  
  87. struct option long_options[] =
  88. {
  89.   {"number", 1, NULL, 'n'},
  90.   {"lines", 0, NULL, 'l'},
  91.   {"blocks", 0, NULL, 'b'},
  92.   {"chars", 0, NULL, 'c'},
  93.   {"quiet", 0, NULL, 'q'},
  94.   {"silent", 0, NULL, 'q'},
  95.   {"verbose", 0, NULL, 'v'},
  96.   {NULL, 0, NULL, 0}
  97. };
  98.  
  99. void
  100. main (argc, argv)
  101.      int argc;
  102.      char **argv;
  103. {
  104.   enum header_mode header_mode = multiple_files;
  105.   int errors = 0;        /* Exit status. */
  106.   int mode = 0;            /* Flags. */
  107.   long number = -1;        /* Number of items to print (-1 if undef.). */
  108.   int c;            /* Option character. */
  109.   int longind;            /* Index in `long_options' of option found. */
  110.  
  111.   program_name = argv[0];
  112.  
  113.   if (argc > 1 && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
  114.     {
  115.       /* Old option syntax; a dash, one or more digits, and one or
  116.      more option letters.  Move past the number. */
  117.       for (number = 0, ++argv[1]; ISDIGIT (*argv[1]); ++argv[1])
  118.     number = number * 10 + *argv[1] - '0';
  119.       /* Parse any appended option letters with getopt. */
  120.       if (*argv[1])
  121.     *--argv[1] = '-';
  122.       else
  123.     argv[1] = "-l";
  124.     }
  125.   while ((c = getopt_long (argc, argv, "n:lbcqv", long_options, &longind))
  126.      != EOF)
  127.     {
  128.       if (c == 0)
  129.     c = long_options[longind].val;
  130.       switch (c)
  131.     {
  132.     case 'n':
  133.       number = atou (optarg);
  134.       if (number == -1)
  135.         error (1, 0, "invalid number `%s'", optarg);
  136.       break;
  137.     case 'l':
  138.       mode &= ~(CHARS | BLOCKS);
  139.       break;
  140.     case 'b':
  141.       mode |= BLOCKS;
  142.       mode &= ~CHARS;
  143.       break;
  144.     case 'c':
  145.       mode |= CHARS;
  146.       mode &= ~BLOCKS;
  147.       break;
  148.     case 'q':
  149.       header_mode = never;
  150.       break;
  151.     case 'v':
  152.       header_mode = always;
  153.       break;
  154.     default:
  155.       usage ();
  156.     }
  157.     }
  158.  
  159.   if (number == -1)
  160.     number = DEFAULT_NUMBER;
  161.  
  162.   if (mode & BLOCKS)
  163.     number *= BLOCKSIZE;
  164.  
  165.   if (header_mode == always
  166.       || header_mode == multiple_files && optind < argc - 1)
  167.     mode |= HEADERS;
  168.  
  169.   if (optind == argc)
  170.     errors |= head_file ("-", mode, number);
  171.  
  172.   for (; optind < argc; ++optind)
  173.     errors |= head_file (argv[optind], mode, number);
  174.  
  175.   exit (errors);
  176. }
  177.  
  178. int
  179. head_file (filename, mode, number)
  180.      char *filename;
  181.      int mode;
  182.      long number;
  183. {
  184.   int fd;
  185.  
  186.   if (!strcmp (filename, "-"))
  187.     {
  188.       filename = "standard input";
  189.       if (mode & HEADERS)
  190.     write_header (filename);
  191.       return head (filename, 0, mode, number);
  192.     }
  193.   else
  194.     {
  195.       fd = open (filename, O_RDONLY);
  196.       if (fd == -1)
  197.     {
  198.       error (0, errno, "%s", filename);
  199.       return 1;
  200.     }
  201.       else
  202.     {
  203.       int errors;
  204.  
  205.       if (mode & HEADERS)
  206.         write_header (filename);
  207.       errors = head (filename, fd, mode, number);
  208.       close (fd);
  209.       return errors;
  210.     }
  211.     }
  212. }
  213.  
  214. void
  215. write_header (filename)
  216.      char *filename;
  217. {
  218.   static int first_file = 1;
  219.  
  220.   if (first_file)
  221.     {
  222.       xwrite (1, "==> ", 4);
  223.       first_file = 0;
  224.     }
  225.   else
  226.     xwrite (1, "\n==> ", 5);
  227.   xwrite (1, filename, strlen (filename));
  228.   xwrite (1, " <==\n", 5);
  229. }
  230.  
  231. int
  232. head (filename, fd, mode, number)
  233.      char *filename;
  234.      int fd;
  235.      int mode;
  236.      long number;
  237. {
  238.   if (mode & (CHARS | BLOCKS))
  239.     return head_chars (filename, fd, number);
  240.   else
  241.     return head_lines (filename, fd, number);
  242. }
  243.  
  244. int
  245. head_chars (filename, fd, chars_to_write)
  246.      char *filename;
  247.      int fd;
  248.      long chars_to_write;
  249. {
  250.   char buffer[BUFSIZE];
  251.   int chars_read;
  252.  
  253.   while (chars_to_write)
  254.     {
  255.       chars_read = read (fd, buffer, BUFSIZE);
  256.       if (chars_read == -1)
  257.     {
  258.       error (0, errno, "%s", filename);
  259.       return 1;
  260.     }
  261.       if (chars_read == 0)
  262.     break;
  263.       if (chars_read > chars_to_write)
  264.     chars_read = chars_to_write;
  265.       xwrite (1, buffer, chars_read);
  266.       chars_to_write -= chars_read;
  267.     }
  268.   return 0;
  269. }
  270.  
  271. int
  272. head_lines (filename, fd, lines_to_write)
  273.      char *filename;
  274.      int fd;
  275.      long lines_to_write;
  276. {
  277.   char buffer[BUFSIZE];
  278.   int chars_read;
  279.   int chars_to_write;
  280.  
  281.   while (lines_to_write)
  282.     {
  283.       chars_read = read (fd, buffer, BUFSIZE);
  284.       if (chars_read == -1)
  285.     {
  286.       error (0, errno, "%s", filename);
  287.       return 1;
  288.     }
  289.       if (chars_read == 0)
  290.     break;
  291.       chars_to_write = 0;
  292.       while (chars_to_write < chars_read)
  293.     if (buffer[chars_to_write++] == '\n' && --lines_to_write == 0)
  294.       break;
  295.       xwrite (1, buffer, chars_to_write);
  296.     }
  297.   return 0;
  298. }
  299.  
  300. /* Write plus error check. */
  301.  
  302. void
  303. xwrite (fd, buffer, count)
  304.      int fd;
  305.      int count;
  306.      char *buffer;
  307. {
  308.   fd = write (fd, buffer, count);
  309.   if (fd != count)
  310.     error (1, errno, "write error");
  311. }
  312.  
  313. /* Convert `str', a string of ASCII digits, into an unsigned integer.
  314.    Return -1 if `str' does not represent a valid unsigned integer. */
  315.  
  316. long
  317. atou (str)
  318.      char *str;
  319. {
  320.   int value;
  321.  
  322.   for (value = 0; ISDIGIT (*str); ++str)
  323.     value = value * 10 + *str - '0';
  324.   return *str ? -1 : value;
  325. }
  326.  
  327. void
  328. usage ()
  329. {
  330.   fprintf (stderr, "\
  331. Usage: %s [-n #] [-lbcqv] [+number #] [+lines] [+blocks] [+chars]\n\
  332.        [+quiet] [+silent] [+verbose] [file...]\n\
  333. \n\
  334.        %s [-#lbcqv] [file...]\n", program_name, program_name);
  335.   exit (1);
  336. }
  337.